﻿

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Audio;

namespace EchoGarden
{
    public class EchoNode : MovingNode
    {
        /// <summary>
        /// List pertaining to the state of the node when it has been located.
        /// </summary>
        private List<Echo> echoes;

        /// <summary>
        /// Random number genrator used 
        /// </summary>
        private Random ranGen;

        /// <summary>
        /// Time echoes should remain visible after being located in milliseconds.
        /// </summary>
        private const float echoVisibilityTime = 3000.0f;
        /// <summary>
        /// Echo time step in milliseconds.
        /// </summary>
        private float echoAgeTimeStep = (float)TimeSpan.FromTicks(333333).TotalMilliseconds;

        /// <summary>
        /// The echo sound effect.
        /// </summary>
        private SoundEffect echoSnd;

        /// <summary>
        /// shadow 1 size
        /// </summary>
        protected const int Shadow1Multiplier = 85;

        /// <summary>
        /// shadow 2 size
        /// </summary>
        protected const int Shadow2Multiplier = 110;

        /// <summary>
        /// Minimum thickness for the ellipse outline. Mapped using Connectedness
        /// </summary>
        protected const int EllipseOutlineMin = 4;

        /// <summary>
        /// Maximum thickness for the ellipse outline. Mapped using Connectedness
        /// </summary>
        protected const int EllipseOutlineMax = 12;

        public EchoNode(Random rand, Texture2D circleTex, SoundEffect echoSound, Point screenSize)
            : base(rand, circleTex, screenSize)
        {
            echoes = new List<Echo>();

            ranGen = rand;
            echoSnd = echoSound;
        }

        public override void Update()
        {
            base.Update();

            for (int i = 0; i != echoes.Count; i++)
            {
                //HACK: No delta time passed. Copied time step directly from GamePage.xaml.xs.
                Echo currentEcho = echoes[i];

                if (currentEcho.Age < 0.0f &&
                    currentEcho.Age + echoAgeTimeStep >= 0.0f)
                {
                    echoSnd.Play(currentEcho.Intensity, ((CurrentY / (float)ScreenSize.Y) * -2.0f) + 1.0f, 0.5f);
                }

                currentEcho.Age += echoAgeTimeStep;
                if (currentEcho.Age < echoVisibilityTime)
                {
                    echoes[i] = currentEcho;
                }
                else
                {
                    echoes.RemoveAt(i);
                    i--;
                }
            }
        }

        /// <summary>
        /// Causes the node to echo out, revealing it's location on screen.
        /// </summary>
        /// <param name="latency">How far away the node is from the ping expressed as a time in miliseconds.</param>
        /// <param name="intensity">Volume and opacity at which the node should echo between 1.0f and 0.0f.</param>
        /// <returns>The echo object.</returns>
        public Echo EchoLocation(float latency, float intensity)
        {
            // Record own position when hit.
            Echo newEcho = new Echo();
            newEcho.Position = CurrentPosition;
            newEcho.Size = Size;
            newEcho.Intensity = intensity;
            newEcho.Age = -latency; // This whole strength thing is botched. Changed my method half way through.
            // Echoes with a negative age don't do anything until they reach zero.
            // So, in order to get them to beep at the right time, I give them a negative age relative the distance
            // they are from the ping (latency).

            echoes.Add(newEcho);

            return newEcho;
        }

        public override void Draw(SpriteBatch sb)
        {
            foreach (Echo currentEcho in echoes)
            {
                if (currentEcho.Age > 0.0f)
                {
                    DrawAtPosition(sb, currentEcho.Position, currentEcho.Size, (1.0f - (currentEcho.Age / echoVisibilityTime)) * currentEcho.Intensity);
                }
            }
        }

        protected void DrawAtPosition(SpriteBatch sb, Vector2 pos, int size, float alpha)
        {
            // center all the ellipses on our position taking in to account their sizes
            var halfSize = size / 2;
            int outlineSize = size + (int)Global.Map(size, NodeSizeMin, NodeSizeMax, EllipseOutlineMin, EllipseOutlineMax);
            int shadow1Size = (int)Global.Map(size, NodeSizeMin, NodeSizeMax, 0.0f, Shadow1Multiplier);
            int shadow2Size = (int)Global.Map(size, NodeSizeMin, NodeSizeMax, 0.0f, Shadow2Multiplier);

            sb.Draw(this.Texture, new Rectangle((int)pos.X - halfSize, (int)pos.Y - halfSize, size, size), null, Color.White * alpha * 0.8f, 0f, Vector2.Zero, SpriteEffects.None, 0.1f);

            halfSize -= (size - outlineSize) / 2;
            sb.Draw(this.Texture, new Rectangle((int)pos.X - halfSize, (int)pos.Y - halfSize, outlineSize, outlineSize), null, Color.White * alpha * 0.4f, 0f, Vector2.Zero, SpriteEffects.None, 0.2f);

            halfSize -= (outlineSize - shadow1Size) / 2;
            sb.Draw(this.Texture, new Rectangle((int)pos.X - halfSize, (int)pos.Y - halfSize, shadow1Size, shadow1Size), null, Color.White * alpha * 0.2f, 0f, Vector2.Zero, SpriteEffects.None, 0.3f);

            halfSize -= (shadow1Size - shadow2Size) / 2;
            sb.Draw(this.Texture, new Rectangle((int)pos.X - halfSize, (int)pos.Y - halfSize, shadow2Size, shadow2Size), null, Color.White * alpha * 0.1f, 0f, Vector2.Zero, SpriteEffects.None, 0.4f);
        }
    }
}
